#include "stdarg.h"
#include "string.h"
#include "stdio.h"
#include "memory"

#include "main.h"
#include "cmsis_os.h"
#include "FreeRTOS.h"
#include "queue.h"
#include "usbh_hid.h"

#include "ili9341.h"
#include "word.h"
#include "gui.h"

//片内额外可使用的内存块
const uint32_t RAM_D1_addr = 0x24000000, RAM_D1_size = 0x80000;
const uint32_t RAM_D2_addr = 0x30000000, RAM_D2_size = 0x48000;
const uint32_t RAM_D3_addr = 0x38000000, RAM_D3_size = 0x10000;

extern void prvUARTCommandConsoleTask(void *pvParameters);

extern UART_HandleTypeDef huart1;
extern SPI_HandleTypeDef hspi1;

void USART1_Printf(char *fmt, ...);
///////////////////////////////////////////////
QueueHandle_t software_1_task_queue;
osThreadId_t software_1_task_Thread;

const osThreadAttr_t software_1_task_attributes = {
	.name = "software_1_task",
	.stack_size = 128 * 5,
	.priority = (osPriority_t)osPriorityNormal};

void software_1_task(void *arg);

void desktop_task(void *arg)
{
	software_1_task_queue = xQueueCreate(1, sizeof(window *));
	window *desktop = new window;

	button *b1 = new button(desktop, "b1", 10, 120, 30, 20);

	word::draw_string(desktop, "desktop", 1, 1, rgb565(255, 255, 0));
	for (;;)
	{
		if(b1->get_status())
		{
			software_1_task_Thread = osThreadNew(software_1_task, NULL, &software_1_task_attributes);
			xQueueSend(software_1_task_queue, &desktop, portMAX_DELAY);
			osDelay(500);
		}

		osDelay(30);
	}
}

void software_1_task(void *arg)
{ //结束任务不会调用类的解析函数，所以需要套一层作用域
	{
		window *desktop = nullptr;
		while(!xQueueReceive(software_1_task_queue, &desktop, portMAX_DELAY));

		std::unique_ptr<windowss> w1(new windowss(desktop, 5, 5, 50, 50));
		window *w1_draw = w1->get_draw_window();

		std::unique_ptr<button> b2(new button(w1_draw, "b2", 10, 10, 20, 20));

		w1_draw->fill(rgb565(30, 30, 100));
		word::draw_string(w1_draw, "w1", 1, 5, rgb565(255, 0, 0));

		for(;;)
		{
			if(b2->get_status())
			{
				w1->disconnect();
				break;
			}
			osDelay(30);
		}
	}
	vTaskDelete(nullptr);
}
/////////////////////////////////////////////////
void screen_task(void *arg)
{
	ili9341::init(&hspi1, GPIOA, gpio_dc_Pin, GPIOA, gpio_cs1_Pin, nullptr, 0);
	window::set_fill_srceen_pt(ili9341::display);
	for (;;)
	{
		window::updata_all_window();
		// lcd1.display(0, 0, window::get_main_window_width(), window::get_main_window_height(), (uint16_t *)window::get_main_window_display_buffer());
		osDelay(30);
	}
}

void cli_task(void *arg)
{
	for (;;)
	{
		prvUARTCommandConsoleTask(nullptr);
	}
}

void led_task(void *arg)
{
	for (;;)
	{
		HAL_GPIO_WritePin(gpio_led_GPIO_Port, gpio_led_Pin, GPIO_PIN_RESET);
		osDelay(100);
		HAL_GPIO_WritePin(gpio_led_GPIO_Port, gpio_led_Pin, GPIO_PIN_SET);
		osDelay(2000);
	}
}

//任务
extern "C"
{
	void init_task(void *arg);
}

extern const osThreadAttr_t init_task_attributes;
extern const HeapRegion_t xHeapRegions[];

const HeapRegion_t xHeapRegions[] =
	{
		{(uint8_t *)RAM_D1_addr, RAM_D1_size}, //外界内存地址，可以被FreeRTOS内存申请函数使用
		{(uint8_t *)RAM_D2_addr, RAM_D2_size},
		{(uint8_t *)RAM_D3_addr, RAM_D3_size},
		{nullptr, 0}};

const osThreadAttr_t desktop_task_attributes = {
	.name = "desktop_task",
	.stack_size = 128 * 5,
	.priority = (osPriority_t)osPriorityNormal};

const osThreadAttr_t init_task_attributes = {
	.name = "init_task",
	.stack_size = 128 * 6,
	.priority = (osPriority_t)osPriorityNormal};

const osThreadAttr_t led_task_attributes = {
	.name = "led_task",
	.stack_size = 128 * 2,
	.priority = (osPriority_t)osPriorityNormal};

const osThreadAttr_t cli_task_attributes = {
	.name = "cli_task",
	.stack_size = 128 * 6,
	.priority = (osPriority_t)osPriorityNormal};

const osThreadAttr_t screen_task_attributes = {
	.name = "screen_task",
	.stack_size = 128 * 8,
	.priority = (osPriority_t)osPriorityNormal};

void init_task(void *arg)
{
	osThreadNew(led_task, NULL, &led_task_attributes);
	osThreadNew(cli_task, NULL, &cli_task_attributes);
	osThreadNew(screen_task, NULL, &screen_task_attributes);
	osThreadNew(desktop_task, NULL, &desktop_task_attributes);

	vTaskDelete(nullptr);
}

//API
void USART1_Printf(char *fmt, ...)
{
	static char Buffer[100];
	va_list arg_ptr;
	va_start(arg_ptr, fmt);
	vsnprintf(Buffer, 100, fmt, arg_ptr);
	va_end(arg_ptr);
	HAL_UART_Transmit_IT(&huart1, (uint8_t *)Buffer, (uint16_t)strlen(Buffer));
	while (huart1.gState != HAL_UART_STATE_READY)
		;
}

unsigned long getRunTimeCounterValue() //FreeRTOS统计任务运行时间的占比用的
{
	return xTaskGetTickCount();
}

// USB Host HID。使用操作系统后，将申请内存的函数换成操作系统提供的，否则无法工作。堆栈不小于128 * 4
// 在Inc里的usbh_conf.h里改前两个宏定义，或者在CubeMX里改。后两个在这改
// #define USBH_PROCESS_PRIO osPriorityNormal //USB的任务没写延时，太占运行时间，所以优先级不要高
// #define USBH_PROCESS_STACK_SIZE ((uint16_t)128 * 4)
#define USBH_malloc new
#define USBH_free delete
void USBH_HID_EventCallback(USBH_HandleTypeDef *phost) //USB的回调函数
{
	HID_TypeTypeDef type = HID_UNKNOWN;

	type = USBH_HID_GetDeviceType(phost);

	switch (type)
	{
	// case HID_KEYBOARD:
	// {
	// 	HID_KEYBD_Info_TypeDef *keyboard_info;

	// 	char ascii;
	// 	keyboard_info = USBH_HID_GetKeybdInfo(phost);

	// 	if (keyboard_info != NULL)
	// 	{
	// 		ascii = USBH_HID_GetASCIICode(keyboard_info);
	// 		if (ascii != 0)
	// 		{
	// 			USART1_Printf("%c", ascii);
	// 		}
	// 	}
	// }
	// break;

	case HID_MOUSE:
	{

		HID_MOUSE_Info_TypeDef *mouse_info;
		mouse_info = USBH_HID_GetMouseInfo(phost);
		// USART1_Printf("mouse_info X%d, Y%d ,button %d %d %d\n", mouse_info->x, mouse_info->y, mouse_info->buttons[0], mouse_info->buttons[1], mouse_info->buttons[2]);
		
		window::in_which_window(mouse_info->x, mouse_info->y, mouse_info->buttons[0]);
	}
	break;

	default:
		break;
	}
}

/*
只要在main源文件里用这些就行了
extern void init_task(void* arg);
extern const osThreadAttr_t init_task_attributes;
extern const HeapRegion_t xHeapRegions[];

vPortDefineHeapRegions(xHeapRegions); //在“开始任务调度”函数之前使用

osThreadNew(init_task, NULL, &init_task_attributes);
*/